
#pragma once

#include <ConnectionBroker/Channels.h>
#include <ConnectionBroker/TcpMessage.h>
#include <ConnectionBroker/Packet.h>
#include <json/json.h>

#include <string>
#include <vector>

namespace ConnectionBroker
{
   namespace PacketUtils
   {
      static Packet channelNumbersToPacket(const std::vector<uint32_t>& channelNumbers)
      {
         Json::Value pMsgJson(Json::objectValue);
         Json::Value channelList(Json::arrayValue);
         for(std::vector<uint32_t>::const_iterator it = channelNumbers.begin(); it != channelNumbers.end(); ++it)
            channelList.append(*it);

         pMsgJson["channels"] = channelList;
         return Packet(Channels::LIBRARY_CHANNEL_SUBSCRIPTION, pMsgJson);
      }
      static Packet channelNumberToPacket(const uint32_t channelNumber)
      {
         std::vector<uint32_t> channels;
         channels.push_back(channelNumber);
         return PacketUtils::channelNumbersToPacket(channels);
      }
      static std::string packetMessageToString(const ConnectionBroker::Packet& packet)
      {
         //Get the json value from the packet.
         Json::Value pMessageJson = packet.message();

         //Convert the json message to a string.
         Json::FastWriter pWriter;
         return pWriter.write(pMessageJson);
      }
      static std::string packetsToString(const std::vector<ConnectionBroker::Packet>& packets)
      {
         Json::Value msgJson(Json::objectValue);
         Json::Value msgList(Json::arrayValue);
         for(std::vector<ConnectionBroker::Packet>::const_iterator it = packets.begin(); it != packets.end(); ++it)
         {
            Packet p = *it;
            Json::Value singleMsg(Json::objectValue);
            Json::Value pHeaderJson(Json::objectValue);
            pHeaderJson["channel"] = p.channel();
            singleMsg["header"] = pHeaderJson;
            singleMsg["message"] = p.message();
            msgList.append(singleMsg);
         }
         msgJson["messages"] = msgList;
         Json::FastWriter writer;
         return writer.write(msgJson);
      }
      static std::string packetToString(const ConnectionBroker::Packet& packet)
      {
         //Get the channel number from the packet.
         uint32_t channel = packet.channel();

         //Get the json value from the packet.
         Json::Value pMessageJson = packet.message();

         //Create a json value enclosing the channel and message.
         Json::Value pOutJson(Json::objectValue);

         Json::Value pHeaderJson(Json::objectValue);
         pHeaderJson["channel"] = channel;

         pOutJson["header"] = pHeaderJson;
         pOutJson["message"] = pMessageJson;

         //Convert json message to a string.
         Json::FastWriter writer;
         return writer.write(pOutJson);
      }
      static TcpMessage packetToTcpMessage(const ConnectionBroker::Packet& packet)
      {
         Json::FastWriter pWriter;
         std::string pMsg(pWriter.write(packet.message()));

         TcpMessage msg;
         msg.body_length(pMsg.length());
         msg.channel(packet.channel());
         msg.body(pMsg.c_str(), pMsg.length());
         msg.encode_header();

         return msg;
      }
      static std::string phpOkToString()
      {
         Json::Value pMsgJson(Json::objectValue);
         Json::Value pEmptyArray(Json::arrayValue);
         pMsgJson["status"] = "OK";
         pMsgJson["statusValue"] = 0;
         pMsgJson["statusCode"] = 0;
         pMsgJson["childrenStatus"] = "OK";
         pMsgJson["message"] = "";
         pMsgJson["extraInfo"] = pEmptyArray;
         pMsgJson["childStatuses"] = pEmptyArray;
         Json::FastWriter writer;
         return writer.write(pMsgJson);
      }
      static Json::Value stringToJson(const std::string& jsonStr)
      {
         Json::Reader pReader;
         Json::Value pJson;
         //Make sure the message is not empty.
         if(jsonStr.empty())
            return Json::nullValue;

         //Make sure the message starts with a {.
         if(jsonStr[0] != '{')
            return Json::nullValue;

         bool parsingSuccessful = pReader.parse(jsonStr, pJson);
         if(!parsingSuccessful)
            return Json::nullValue;

         return pJson;
      }
      static Packet tcpMessageToPacket(const TcpMessage& pTcpMessage)
      {
         std::string message(pTcpMessage.body());
         const uint32_t channel = pTcpMessage.channel();
         Json::Value pMessageJson(stringToJson(message));
         if(pMessageJson.isNull())
            return Packet(0, pMessageJson);

         return Packet(channel, pMessageJson);
      }
      static Packet stringToPacket(const std::string& packetStr)
      {
         Json::Value pMessageJson(stringToJson(packetStr));
         if(!pMessageJson.isObject())
            return Packet(0, pMessageJson);

         Json::Value pHeaderJson(pMessageJson.get("header", Json::nullValue));
         if(!pHeaderJson.isObject())
            return Packet(0, pMessageJson);
         Json::Value pChannelJson = pHeaderJson.get("channel", Json::nullValue);
         if(pChannelJson.isNull())
            return Packet(0, pMessageJson);

         uint32_t channel = pChannelJson.asUInt();
         Json::Value msg = pMessageJson.get("message", Json::nullValue);

         if(msg.isNull())
            return Packet(0, pMessageJson);

         return Packet(channel, msg);
      }
   }
}

